﻿using System;
using System.Windows.Automation;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Automation.Peers;
using System.Timers;
using System.Windows.Controls;
using Tedds_Tool.Automatables;
using Compiled_Tests;
using Compiled_Tests.ProcessWrappers;
using Compiled_Tests.AutomationAbstractions;
using CommonInterfaces.Models;
using LEET.LEETCommon;
using LEET.CommonInterfaces.Automation;


namespace Tedds_Tool
{
    /// <summary>
    /// Tape represents an individual parent GUI element, from which
    /// it is assumed we may acquire a WindowPattern, which a Recorder
    /// is monitoring.
    /// </summary>
    public class Tape : ITape, IDisposable
    {

        #region Attributes

        /// <summary>
        /// The root UI element.  The events of all descendants of _main 
        /// are to be recorded.
        /// </summary>
        private IObservableWidget _main;

        /// <summary>
        /// Denotes whether or not this Tape is still recording events.
        /// </summary>
        EventDelegate delagate;
        internal IList<AutomationElementEventListener> listeners;
        IList<ILEETHackModual> hacks;
        IProcess target;
        #endregion


        /// <summary>
        /// Used to encapsulate all event handlers related to a Recorder.
        /// </summary>
        /// <param name="cd">
        /// A reference to the Recorder object, necessary for callbacks.
        /// </param>
        /// <param name="ae">
        /// The root element, the children of which this Tape should be monitoring.
        /// </param>
        public Tape(IProcess p, EventDelegate delagate, IList<ILEETHackModual> hacks) 
        {
            this.hacks = hacks;
            target = p;
            _main = p.RootWidget;

            this.delagate = delagate;  //Necessacy for callbacks
            listeners = new List<AutomationElementEventListener>();
        }

        public void AddListener(AutomationElementEventListener listener)
        {
            listener.Handlers += Add_Event;
            listeners.Add(listener);
        }

        /// <summary>
        /// Allows the addition of Event_Pairs to Recorder's list of recorded 
        /// events as long as they are not null.  The only time I can think of 
        /// this happening, so long as Tape continues to be programmed the way
        /// it is now, is in events added by Recorder and the GUI directly.
        /// </summary>
        /// <param name="ep">
        /// The Event_Pair to add to the Recorder's list of recorded events.
        /// </param>
        private void Add_Event(IProcess proc, IEvent_Pair ep) 
        {
            if (ep != null && delagate != null) 
            {
                delagate(target, ep);
            }
        }

        /// <summary>
        /// Unlinks this Tape from any events it may have been monitoring, 
        /// changes active to false such that Recorder can understand that 
        /// it is no longer recording events, and nulls out its target.
        /// At least the nulling of event handlers is necessary, but I'm 
        /// debating just nulling the Tape itself from Recorder instead.
        /// </summary>
        public void Dispose()
        {
            try
            {
                foreach(AutomationElementEventListener listener in listeners)
                    listener.Dispose();
            }
            catch (ArgumentNullException) { /*not actually a problem, means _main closed before we caught it*/ }
            listeners.Clear();
            delagate = null;
            _main.Dispose();
        }

        /// <summary>
        /// Returns the activity state of this Tape.
        /// </summary>
        /// <returns>
        /// True if the _main element is still open, else false.
        /// </returns>
        public bool Listening
        {
            get {
                if (_main.ProccessHasExited)
                {
                    Dispose();
                    return false;
                }
                else
                {
                    foreach (AutomationElementEventListener listener in listeners)
                    {
                        if (listener.Listening)
                        {
                            return true;
                        }
                    }
                    return false;
                }
            }
        }




        public string ProcessName { get {
            return target.Name;
        } }

        public IElementState State
        {
            get{
                return new ElementState(_main.ae, hacks);
            }
        }

        public IProcess Process
        {
            get
            {
                return target;
            }
        }
    }
}
